<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>Example</title>
</head>
<body>
</body>
<script type="text/javascript">

    //js实现发布订阅功能
    class Watcher {
        constructor() {
            this.topics = {}; //订阅列表
            this.uid = -1; //唯一标示
        }
        //订阅
        subscribe(topic, fn) {
            if(!this.topics[topic]){
                this.topics[topic] = [];
            } 
            this.topics[topic].push({
                fn,
                uid: ++this.uid 
            });
            return this.uid;
        }
        //发布
        publish(topic) {
            if(this.topics[topic]){
                let args = [...arguments];
                args.shift();
                this.topics[topic].forEach(({fn}) => {
                    fn.apply(this, args);
                })
            }
            return this;
        }
        //取消订阅，多个的话使用数组
        unsubscribe(topic) {
            if(this.topics[topic]){
                let args = [...arguments];
                args.shift();
                if(Array.isArray(args[0])) args = [...args[0]];
                this.topics[topic] = this.topics[topic].filter(({uid}) => !args.includes(uid));
            }
            return this;
        }
    }

    const pubsub = new Watcher();
    let onClick1 = pubsub.subscribe('onClick', (params) => {
        console.log('onClick1');
        console.log(params);
    })
    let onClick2 = pubsub.subscribe('onClick', (params) => {
        console.log('onClick2');
        console.log(params);
    })
    pubsub.subscribe('onChange', (params) => {
        console.log('onChange');
        console.log(params);
    })
    pubsub.subscribe('onKeyup', (params) => {
        console.log('onKeyup');
        console.log(params);
    })
</script> 

</html>